package time_windown

import (
	"sync"
	"time"
)

// 固定时间窗口控频
type StaticWindowRateLimiter struct {
	windowSize time.Duration
	startTime  time.Time // 当前窗口的起始时间

	dataBucket map[string][]time.Time // key: 标识一个对象 | val: 对象出现的时间记录
	maxCount   int                    // 最大频率

	mu sync.RWMutex
}

func (r *StaticWindowRateLimiter) Allow(key string) bool {
	r.mu.Lock()
	defer r.mu.Unlock()

	now := time.Now()

	// 如果窗口已经过期，其中数据直接失效，重新计算窗口的起始位置
	if r.startTime.Add(r.windowSize).Before(now) {
		if len(r.dataBucket) > 0 { // 空窗口就不需要销毁，减少内存分配
			r.dataBucket = make(map[string][]time.Time) // 旧数据销毁
		}

		// now时间点的窗口开始时间 = 旧窗口开始时间点 + ((当前时间点 - 旧窗口开始时间点) / 窗口长度)*窗口长度
		x := now.Sub(r.startTime).Nanoseconds() / r.windowSize.Nanoseconds()
		r.startTime = r.startTime.Add(time.Duration(x) * r.windowSize)
	}

	r.dataBucket[key] = append(r.dataBucket[key], now)

	// if len(r.dataBucket[key]) > r.maxCount {
	// 	return false
	// }
	// return true

	return len(r.dataBucket[key]) <= r.maxCount
}

// 创建固定时间窗口式的对象频率控制
func NewStaticRateLimiter(windowSize time.Duration, maxCount int) *StaticWindowRateLimiter {
	res := &StaticWindowRateLimiter{
		windowSize: windowSize,
		maxCount:   maxCount,
		startTime:  time.Now(),
		dataBucket: make(map[string][]time.Time),
	}

	return res
}
